#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <pthread.h>    /* POSIX Threads */
#include <arpa/inet.h>

/**********************************************************************************
 *  #define
 **********************************************************************************/

#define PORT 7000
#define CLIENTPORT 9000
#define PORTSS 9002 /*PORT Storage Server*/
#define IPStorageServer	((in_addr_t)0xC0A80197 ) /* Inet 192.168.1.151.  */ //
#define BUFFSIZE 256
#define MAX_CLIENTS 5

/**********************************************************************************
 *   global data
 **********************************************************************************/

struct sockaddr_in gv_address; // struct sockeaddr_in defined in socket.h
struct sockaddr_in ss_address; // struct sockeaddr_in defined in socket.h
struct sockaddr_in peer_address; // struct sockeaddr_in defined in socket.h

struct file_inf {
	char name[20];
	long size;
	int nr_of_blocks;
	char ip[16];
	char* infoFile;
}download_files[7];//global list with the download files.
char checkEmptyPlaces[7] = {0,0,0,0,0,0,0};//used to know which places in the array download_files are taken or not.

char* inputBuffer;
char EOC = 0; // o: none, go on. 1: end of command received.: needed for accepting commands over multiple lines.
char downloading = 0; // Downloader-thread status.
char downloader_thread_is_running = 1;
pthread_t tarray[3]; /* array of thread variables */
char needtoclean = 1;

/**********************************************************************************
 *  function prototypes
 **********************************************************************************/

void parse_input(char* input, int* sPtr);
void start_downloader_thread(void);
void stop_downloader_thread(void);
void init_downloader_thread(void);
void send_rt_infofiles(int* sPtr);
void get_File(char filename[BUFFSIZE], int blocknr, int* sPtr);
void add_DownloadFile(char name[20],long size, int nr_of_blocks,char ip[16], char infoFile[64*1024]);
void start_Download(void);
void downloader_thread(void);
void stop_Download(void);
int write_to_storageServer(int s,char filename[20], long filesize, int blocknr,char block[64*1024]);
int init_client_socket(void);
int init_server_socket(void);
void handle_client(int s);
void handle_server(int* sPtr);
void close_socket(int);
void start_client(void);
void start_server(void);
int connectoToStorageServer(void);

/* -----------------------------------------------------------------------------------------------------------
 * Function:	parse_input
 * Purpose:     Parses the input from the Java client.
 * Arguments:	char* input
 * Argument contents:
 * START<sp><filename><sp><filesize><sp><nr_of_blocks><sp><ip><sp><inhoud !info file>\n
 * STOP
 * Return value: Failure: void
 *------------------------------------------------------------------------------------------------------------
 */
void parse_input(char* input, int* sPtr){
	printf("Parsing input: %s\n", input);
	int s = *sPtr;
	if(strncmp(input, "EOC", strlen("EOC"))==0){
		printf("EOC received.\n");
		int cntr;
		needtoclean = 1;
		// Parse input.
		if(strncmp(inputBuffer, "START", strlen("START")) == 0){
			printf("START command detected.\n");
			char filename[20] = {0};
			long filesize;
			int nr_of_blocks;
			char ip[16] = {0};
			char* infoFile = malloc(64*1024);
			int arraycntr;
			for(arraycntr=0;arraycntr<(64*1024);arraycntr++){
				char dinkie = 0;
				infoFile[arraycntr] = dinkie;
			}

			int counter;
			char maxbuffer = 5; // number of parameters read.
			char tempbuffer[maxbuffer][BUFFSIZE]; // buffer max size;
			char argument = 0; //index for tempbuffer
			int buffercounter = 0; // index for argument character.
			printf("Number of elements in inputbuffer: %i", strlen(inputBuffer));
			printf("Contents of inputbuffer: %s\n",inputBuffer);
			for(counter=0;counter<strlen(inputBuffer)-1;counter++){
				if(inputBuffer[counter] == ' '){
					argument++;
					buffercounter = 0;
					if(argument>maxbuffer){break;}
				}else{
					if(argument>0&&argument !=5&&argument!=1&&argument!=4){// Exclude the first word. 'START'  in this case.
						tempbuffer[argument-1][buffercounter] = inputBuffer[counter];
					}else if(argument == 1){
						filename[buffercounter] = inputBuffer[counter];
					}else if(argument == 4){
						ip[buffercounter] = inputBuffer[counter];
					}else if(argument == 5){
						infoFile[buffercounter] = inputBuffer[counter];
					}
					buffercounter++;
				}
			}

			filesize = atoi(tempbuffer[1]);
			nr_of_blocks = atoi(tempbuffer[2]);

			printf("Parsed input! Filename: %s \n", filename);
			printf("IP: %s\n",ip);
			//printf("Filesize: %i\n", filesize);
			printf("Nr_of_blocks: %i\n", nr_of_blocks);
			printf("infoFile: %s\n", infoFile);
			// Add file to queue.
			add_DownloadFile(filename,filesize,nr_of_blocks,ip,infoFile);
			start_downloader_thread();
			//start_Download();
			char *message = "OK\n";
			printf("Sending message: %s\n", message);
			send(s, message, strlen(message), 0);
		}else if(strncmp(inputBuffer, "STOP-DOWNLOAD", strlen("STOP-DOWNLOAD")) == 0){
			puts("STOP-DOWNLOAD command received.\n");
			stop_Download();
			stop_downloader_thread();
			char *message = "OK\n";
			printf("Sending message: %s\n", message);
			send(s, message, strlen(message), 0);
		}else if(strncmp(inputBuffer, "GET-RT-INFO-FILES", strlen("GET-RT-INFO-FILES")) == 0){
			// return info files
			printf("GET-RT-INFO-FILES received.\n");
			send_rt_infofiles(sPtr);
		}else if(strncmp(inputBuffer, "GET-FILE", strlen("GET-FILE")) == 0){
			// get-file<sp><filename>
			char filename[BUFFSIZE] = {0};
			char charblocknr[BUFFSIZE] = {0};
			int blocknr;
			//TODO: Onderstaand kan worden vervangen door sscanf/sprintf combi
			char argument = 0;
			int charcounter = 0, c;
			for(c=0;c<strlen(inputBuffer);c++){
				if(inputBuffer[c] == ' '){
					argument++;
					charcounter = 0;
				}else{
					if(argument==1){
						filename[charcounter] = inputBuffer[c];
					}else if(argument==2){
						charblocknr[charcounter] = inputBuffer[c];
					}
					charcounter++;
				}
			}
			blocknr = atoi(charblocknr);
			get_File(filename, blocknr, sPtr);
		}else{
			printf("Received EOC without command. Sending fail.\n");
			char *message = "FAIL\n";
			send(s, message, strlen(message), 0);
		}
		//Clean inputBuffer.
		for(cntr=0;cntr<(64*1024);cntr++){
			char dinkie = 0;
			inputBuffer[cntr] = dinkie;
		}
	}else{
		printf("input: %s\n",input);
			printf("gaat goed:)\n");
			puts("Okidoki!");
			if(needtoclean == 1){
				printf("needtoclean\n");
				needtoclean = 0;
				//Clean inputBuffer.
				int cntr;
				for(cntr=0;cntr<(64*1024);cntr++){
					char dinkie = 0;
					inputBuffer[cntr] = dinkie ;
				}
			}
			printf("End needtoclean\n");
			// No EOC, continue appending command.
			strcat(inputBuffer,input);
			printf("Added input to buffer, now containing: %s\n", inputBuffer);

	}
	//			message = (char*)"INFO-FILE test.exe 100 20 192.168.1.1 00000000001111111111\n";
	//char *message = "EOC\n";
	//send(s, message, strlen(message), 0);

}

void start_downloader_thread(){
	downloader_thread_is_running = 1;
}

void stop_downloader_thread(){
	downloader_thread_is_running = 0;
}

void init_downloader_thread(){
	downloader_thread_is_running = 0;
	puts("Creating downloader thread");
	int rv = pthread_create (&tarray[2], NULL, (void *)&downloader_thread, NULL);
	if (rv != 0) {
		perror("Error creating downloader_thread");
		//exit(EXIT_FAILURE);
	}
}

void downloader_thread(){
	char true = 1;
	while(1){
		int nr_of_blocks = download_files[0].nr_of_blocks;
		long size = download_files[0].size; // hebbe we niets aan, mrgoed.
		int current_blocknr = 0, cntr;
		while(downloader_thread_is_running == 1){

			int s;
			char *buffer = malloc(BUFFSIZE);
			char *appendbuffer = malloc(64*1024);
			int cntrt;
			for(cntrt=0;cntrt<(64*1024);cntrt++){
				char dinkie = 0;
				appendbuffer[cntrt] = dinkie;
			}
			buffer[0] = '\0';
			int nr_bytes_recv = 0;
			FILE *fp;
			if(true == 1){
				printf("Iterating downloader_thread.\n");
				true = 0;

				for(cntr=0;cntr<nr_of_blocks;cntr++){
					//iterate infofile, finding first block to start with.
					if(download_files[0].infoFile[cntr]=='0'){
						current_blocknr = cntr; // first block;
						printf("Found first blocknr: %i\n",current_blocknr);
						break;
					}
				}

				int rv = -1; // return value, default is -1(error.)
				s = socket(AF_INET, SOCK_STREAM, 0);
				if(s < 0) {
					perror("Error creating socket");
					exit(EXIT_FAILURE);
				}

				peer_address.sin_family = AF_INET;
				peer_address.sin_addr.s_addr = inet_addr(download_files[0].ip);
				peer_address.sin_port = htons(CLIENTPORT);
				puts("Trying to connect to peer...");
				while (rv < 0) {
					rv = connect(s, (struct sockaddr *)&peer_address, sizeof(peer_address));
					puts("Reconnecting to peer/apple/orange.");
				}

				fp=fopen("file.txt", "w");
			}
			// need to send: GET <sp><filename><sp><blocknr>
			char message[BUFFSIZE] ={0};
			strcat(message, (char*)"GET ");
			strcat(message, (char*)download_files[0].name);
			strcat(message, (char*)" ");
			char blocknrtofech[32] = {0};
			sprintf(blocknrtofech, "%d", current_blocknr);
			strcat(message, (char*)blocknrtofech);
			strcat(message, (char*)"\n");
			printf("Sending message: %s\n", message);
			send(s, message, strlen(message), 0);

			nr_bytes_recv = 1;

			while(nr_bytes_recv > 0){
				// receive data in buffer
				nr_bytes_recv = recv(s, buffer, BUFFSIZE, 0);

				if (nr_bytes_recv > BUFFSIZE) {
					perror("Buffer too small");
					exit(EXIT_FAILURE);
				}

				buffer[nr_bytes_recv]= '\0'; // close string
				printf("Client received : %s", buffer);
				printf("Number of elements in buffer: %i\n",strlen(buffer));
				fprintf(fp, buffer);
				strcat(appendbuffer,buffer);
				printf("Buffer contains: %s\n", buffer);
				printf("Appendbuffer contains: %s\n", appendbuffer);
				//write_to_storageServer(int s,char filename[20], long filesize, int blocknr,char block[64*1024])
			}
			int storage = connectoToStorageServer();
			write_to_storageServer(storage,download_files[0].name,size,current_blocknr,appendbuffer);
			close_socket(storage);
			fclose(fp);

			current_blocknr++;

			if(current_blocknr >= nr_of_blocks){
				downloader_thread_is_running = 0;
				// Buffer downloaded, append to file.
			}
		}
		if(true == 0){
			true = 1;
			printf("Iterating downloader_thread stopped.\n");
		}

	}
}


void send_rt_infofiles(int* sPtr){
	int s = *sPtr;
	int cntr;
	printf("Iterating download_files.\n");
	for(cntr = 0;cntr<8;cntr++){
		if(checkEmptyPlaces[cntr]==1){
			char buffer[64*1024];
			printf("Iteration number: %i\n",cntr);
			strcat(buffer, "INFO-FILE ");
			strcat(buffer, (char*)download_files[cntr].name);
			char size[64] = {0};
			//sprintf(size, "%d", download_files[cntr].size);
			strcat(buffer, (char*)size);
			char blocks[32] = {0};
			sprintf(blocks, "%d", download_files[cntr].nr_of_blocks);
			strcat(buffer, blocks);
			strcat(buffer, download_files[cntr].ip);
			strcat(buffer, download_files[cntr].infoFile);
			if(cntr==7){
				strcat(buffer, (char*)"\n");
			}else{
				strcat(buffer, (char*)" ");
			}
			printf("Sending message: %s\n", buffer);
			send(s, buffer, strlen(buffer), 0);
		}
	}

	char *message = "EOC\n";
	printf("Sending message: %s\n", message);
	send(s, message, strlen(message), 0);
}

void get_File(char filename[BUFFSIZE], int blocknr, int* sPtr){
	int rv = 0;
	int s = *sPtr;
	printf("Executing get_File()");
	char *message = "Testcontents\n";
	printf("Sending: %s\n",message);
	rv = send(s, message, strlen(message), 0);
	message = "EOC\n";
	printf("Sending message: %s\n", message);
	printf("Sending: %s\n",message);
	rv = send(s, message, strlen(message), 0);
}

/* -----------------------------------------------------------------------------------------------------------
 * Function:	connectoTStorageServerTCP, TCP_NODELAY
 * Purpose:     this method will try to make a socket connection with the storage server.
 * 				NOTE: no permanent connection, so setup a connection every time again.
 * Arguments:	none
 * Return value: Failure: -1 , Success: 0
 *------------------------------------------------------------------------------------------------------------
 */
int connectoToStorageServer(){
	int rv = 0; // return value
	printf("%s\n", "Connect with the StorageServer\n");
	int s = socket(AF_INET, SOCK_STREAM, 0);
	if(s < 0) {
		perror("Error creating socket");
		exit(EXIT_FAILURE);
	}
	ss_address.sin_family = AF_INET;
	ss_address.sin_addr.s_addr = htonl(IPStorageServer);
	ss_address.sin_port = htons(PORTSS);

	rv = connect(s, (struct sockaddr *)&ss_address, sizeof(ss_address));
	if (rv < 0) {
		perror("Error connecting to storage server socket\n");
		return rv;
	}
	printf("Connected\n");
	return s;
}

/* -----------------------------------------------------------------------------------------------------------
 * Function:	get_from_storageServer
 * Purpose:     this method will get blocks one-by-one from the storage server.
 * Arguments:	format <GET> <filename> <filesize> <blocknr>
 * Return value: block[64*1024]
 *------------------------------------------------------------------------------------------------------------
 */
char* get_from_storageServer(int s,char filename[20], int blocknr){
	int rv;

	// create and init a char buffer
	char *buffer = malloc(BUFFSIZE);
	char buff[64*1024];
	char temp[64*1024];
	strcpy(buffer,"GET");
	strcat(buffer," ");
	strcat(buffer,filename);
	strcat(buffer," ");
	sprintf(temp, "%d",blocknr);
	strcat(buffer,temp);
	strcat(buffer,"\n");

	printf("router sends to storage server %s\n",buffer);
	rv = send(s,buffer,strlen(buffer), 0);
	if (rv < 0) {
		perror("Error sending\n");
		exit(EXIT_FAILURE);
	}
	int nr_bytes_recv = 0;
	while (nr_bytes_recv < (64*1024)){
		// receive data in buffer
		nr_bytes_recv += recv(s, buffer, BUFFSIZE, 0);
		strcat(buff,buffer);
		//if (nr_bytes_recv > BUFFSIZE) {
		//	perror("Buffer too small");
		//	exit(EXIT_FAILURE);
		//}
	}
	//printf("Client received : %s",buff );
	buffer[nr_bytes_recv]= '\0'; // close string
	return buff;
}

/* -----------------------------------------------------------------------------------------------------------
 * Function:	write_to_storageServer
 * Purpose:     this method will write  blocks one-by-one to the storage server.
 * Arguments:	format <POST> <filename> <size of file> <blocknr> <block>
 * Return value: Failure: -1 , Success: 0
 *------------------------------------------------------------------------------------------------------------
 */
int write_to_storageServer(int s,char filename[20], long filesize, int blocknr,char block[64*1024]){
	int rv;
	// create and init a char buffer
	char *buffer = malloc(BUFFSIZE);
	char temp[64*1024];
	strcpy(buffer,"POST");
	strcat(buffer," ");
	strcat(buffer,filename);
	strcat(buffer," ");
	sprintf(temp, "%ld", filesize);
	strcat(buffer,temp);
	strcat(buffer," ");
	sprintf(temp, "%d", blocknr);
	strcat(buffer,temp);
	strcat(buffer," ");
	strcat(buffer,block);
	strcat(buffer,"\n");

	printf("router sends to Storageserver %s\n",buffer);

	rv = send(s,buffer,strlen(buffer), 0);
	if (rv < 0) {
		perror("Error sending\n");
		exit(EXIT_FAILURE);
	}
	return rv;
}
/* -----------------------------------------------------------------------------------------------------------
 * Function:	remove_from_storageServer
 * Purpose:     this method will remove a file from the storage server, based on filename[20]
 * Arguments:	none
 * Return value: Failure: -1 , Success: 0
 *------------------------------------------------------------------------------------------------------------
 */
int remove_from_storageServer(int s,char filename[20]){
	int rv;
	// create and init a char buffer
	char *buffer = malloc(BUFFSIZE);
	strcpy(buffer,"REMOVE");
	strcat(buffer," ");
	strcat(buffer,filename);
	strcat(buffer,"\n");

	rv = send(s,buffer,strlen(buffer), 0);
	printf("router sends to Storageserver %s\n",buffer);
	if (rv < 0) {
		perror("Error sending\n");
		exit(EXIT_FAILURE);
	}

	return rv;
}
/* -----------------------------------------------------------------------------------------------------------
 * Function:	add_DownloadFile
 * Purpose:     this method will add the info file with completed and uncompleted blocks to the download_files.
 * Arguments:
 * Return value: /
 *------------------------------------------------------------------------------------------------------------
 */
void add_DownloadFile(char name[20],long size, int nr_of_blocks,char ip[16], char* info_File){
	printf("Start of add_Downloadfile()\n");
	int i = 0;
	for(i=0;i<(sizeof(download_files)/sizeof(download_files[0]));i++){
		if(checkEmptyPlaces[i] == 0){
			printf("Start of clearing infofile.\n");
			int arraycntr;
			for(arraycntr=0;arraycntr<(64*1024);arraycntr++){
				char dinkie = 0;
				download_files[i].infoFile[arraycntr] = dinkie;
			}
			printf("End of clearing infoFile.\n");
			checkEmptyPlaces[i] = 1;
			memcpy(download_files[i].name, name, 20*sizeof(char));
			printf("%s ",download_files[0].name);
			download_files[i].size = size;
			printf("%ld ",download_files[0].size);
			download_files[i].nr_of_blocks =nr_of_blocks;
			printf("%d ",download_files[0].nr_of_blocks);
			memcpy(download_files[i].ip, ip, 16*sizeof(char));
			printf("%s ",download_files[0].ip);
			memcpy(download_files[i].infoFile,info_File,strlen(info_File));
			printf("%s ",download_files[0].infoFile);
			break;
		}
	}

}

/* -----------------------------------------------------------------------------------------------------------
 * Function:	start_Download
 * Purpose:     this method will start the dowload function.
 * Arguments:	none
 * Return value: /
 *------------------------------------------------------------------------------------------------------------
 */
void start_Download(){

}



/* -----------------------------------------------------------------------------------------------------------
 * Function:	start_Download
 * Purpose:     this method will start the dowload function.
 * Arguments:	none
 * Return value: /
 *------------------------------------------------------------------------------------------------------------
 */
void stop_Download(){
	int c;
	for(c=0;c<7;c++)
		checkEmptyPlaces[c]=0;
}

/* -----------------------------------------------------------------------------------------------------------
 * Function:	init_socket
 * Purpose:	creates a socket and connects it to server socket
 * Arguments: 	none
 * Return value:    Success: returns socket descriptor of new socket
 *		    Failure: none
 *------------------------------------------------------------------------------------------------------------
 */

int init_client_socket(void)
{	 
	int rv = -1; // return value, default is -1(error.)
	int s = socket(AF_INET, SOCK_STREAM, 0);
	if(s < 0) {
		perror("Error creating socket");
		exit(EXIT_FAILURE);
	}

	gv_address.sin_family = AF_INET;
	gv_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	printf("Client ipdata: %d\n",gv_address.sin_addr.s_addr);
	gv_address.sin_port = htons(PORT);
	puts("Trying to open server socket...");
	while (rv < 0) {
		rv = connect(s, (struct sockaddr *)&gv_address, sizeof(gv_address));
		puts("Error connecting to server socket");
	}
	return s;
}

int init_server_socket()
{
	int rv; // return value
	int s = socket(AF_INET, SOCK_STREAM, 0);
	if(s < 0) {
		perror("Error creating socket");
		exit(EXIT_FAILURE);
	}

	gv_address.sin_family = AF_INET;
	gv_address.sin_addr.s_addr = INADDR_ANY;
	gv_address.sin_port = htons(PORT);

	rv = bind(s, (struct sockaddr *)&gv_address, sizeof(gv_address));
	if (rv < 0) {
		perror("Error binding to socket");
		exit(EXIT_FAILURE);
	}
	puts("Socket initialized");
	return s;
}

/* -----------------------------------------------------------------------------------------------------------
 * Function:	close_socket
 * Purpose:	closes a socket
 * Arguments: 	socket desciptor
 * Return value:    Success: none
 *		    Failure: none
 *------------------------------------------------------------------------------------------------------------
 */

void close_socket(int s)
{	 
	int rv = close(s);
	if (rv < 0) {
		perror("Error closing socket");
		exit(EXIT_FAILURE);
	}
	puts("Socket closed");
}

/* -----------------------------------------------------------------------------------------------------------
 * Function:	listen and handle on a socket
 * Purpose:	listen for incoming connetions; spawn thread for each incoming connection
 * Arguments: 	master socket desciptor
 * Return value: Success: none
 *		 Failure: none
 *------------------------------------------------------------------------------------------------------------
 */


void listen_and_handle(int ms)
{
	int rv; // return value
	int cs; // child socket descriptor
	int i = 0;
	pthread_t tarray[2]; /* array of thread variables */

	// listen for incoming connection, MAX_CLIENTS connections pending
	puts("Waiting for incoming connections");
	rv = listen(ms, MAX_CLIENTS);
	if (rv < 0) {
		perror("Error listening to socket");
		exit(EXIT_FAILURE);
	}

	for (i=0; i < MAX_CLIENTS; i++) {
		// accept incoming connection
		unsigned int addr_len = sizeof(gv_address);
		cs = accept(ms, (struct sockaddr *)&gv_address, &addr_len);
		if (cs < 0) {
			printf("Error accept");
			exit(EXIT_FAILURE);
		}

		rv = pthread_create (&tarray[i], NULL, (void *)&handle_server, (void *)&cs);
		if (rv != 0) {
			perror("Error creating thread");
			exit(EXIT_FAILURE);
		}
		puts("Client accepted");
	}

	// now wait for all threads to terminate
	for (i=0; i < MAX_CLIENTS; i++) {
		rv = pthread_join(tarray[i], NULL);
		if (rv != 0) {
			perror("Error listening to socket");
			exit(EXIT_FAILURE);
		}
	}
}


/* -----------------------------------------------------------------------------------------------------------
 * Function:	handle a socket (receive and send)
 * Purpose:	if a string "STOP" is received then close connection,
 *		else echoe received string back
 * Arguments: 	socket desciptor, thread id
 * Return value: Success: none
 *		 Failure: none
 *------------------------------------------------------------------------------------------------------------
 */

void handle_server(int* sPtr)
{
	int rv = 0; // return value
	int s = *sPtr;

	// create and init a char buffer
	char *buffer = malloc(BUFFSIZE);
	buffer[0] = '\0';

	int stop_received = 0;
	int nr_bytes_recv = 0;

	// Init inputbuffer.
	inputBuffer = malloc(64*1024);
	download_files[0].infoFile = malloc(64*1024);
	download_files[1].infoFile = malloc(64*1024);
	download_files[2].infoFile = malloc(64*1024);
	download_files[3].infoFile = malloc(64*1024);
	download_files[4].infoFile = malloc(64*1024);
	download_files[5].infoFile = malloc(64*1024);
	download_files[6].infoFile = malloc(64*1024);
	download_files[7].infoFile = malloc(64*1024);


	while (! stop_received) {
		puts("Start of !stop_received");
		// receive data in buffer
		nr_bytes_recv = recv(s, buffer, BUFFSIZE, 0);
		puts("after receive");
		if(nr_bytes_recv == -1){
			puts("Connection reset unexpectedly. Closing this thread..");
			rv = close(s);
			stop_received = 1;
		}

		if (nr_bytes_recv > BUFFSIZE) {
			perror("Buffer too small");
			exit(EXIT_FAILURE);
		}

		buffer[nr_bytes_recv]= '\0'; // close string
		printf("Server received : %s", buffer);

		if(strncmp(buffer, "TERM", 4) == 0) {
			char *message = "Closing server socket...\n";
			rv = send(s, message, strlen(message), 0);
			if (rv < 0) {
				perror("E	buffer[0] = '\0';rror sending(in stop)");
				exit(EXIT_FAILURE);
			}
			puts("Closing server socket.");
			rv = close(s);
			if (rv < 0) {
				perror("Error closing socket");
				exit(EXIT_FAILURE);
			}
			stop_received = 1;

		} else {
			// echo message
			// rv = send(s, buffer, nr_bytes_recv,0);
			if (rv < 0) {
				puts("Error in sending(in send echo)");
				exit(EXIT_FAILURE);
			}
			parse_input(buffer,&s);
		}
	}
}


/* -----------------------------------------------------------------------------------------------------------
 * Function:	handle a socket (receive and send)
 * Purpose:	if a string "STOP" is send then server will close connection,
 *		else server will echo the send string back to client
 * Arguments: 	socket desciptor
 * Return value: Success: none
 *		 Failure: none
 *------------------------------------------------------------------------------------------------------------
 */

void handle_client(int s)
{
	int rv = 0; // return value

	printf("%s\n", "Max clients = 3");
	printf("%s\n", "Type your input; \"STOP<return>\" will stop the server and ^D will stop the client");
	// finish with ctrl-d

	// create and init a char buffer
	char *buffer = malloc(BUFFSIZE);
	buffer[0] = '\0';

	//int nr_bytes_recv = 0;

	while (!feof(stdin)) {
		fgets(buffer, BUFFSIZE, stdin);
		rv = send(s, buffer, strlen(buffer), 0);
		if (rv < 0) {
			perror("Error sending(in client)");
			exit(EXIT_FAILURE);
		}

	}
}

void start_client(){
	int s = 0; // master socket descriptor
	s = init_client_socket();
	handle_client(s);
	close_socket(s);
}

void start_server(){
	int ms; // master socket descriptor
	ms = init_server_socket();
	listen_and_handle(ms);
	close_socket(ms);
}

/* -----------------------------------------------------------------------------------------------------------
 * Function:	main
 * Purpose:     -
 * Arguments:	none
 * Return value: Success: 0
 *		 Failure: none
 *------------------------------------------------------------------------------------------------------------
 */

int main()
{
	//int s; // master socket descriptor
	//s = connectoToStorageServer();
	//write_to_storageServer(s,"test.text",133120,0,"111111111100000000001111111111000000000011111111110000000000111111111100000000001111111111000000000011111111110000000000111111111100000000001111111111000000000011111111110000000000111111111100000000001111111111000000000011111111110000000000111111111100000000001111111111000000000011111111110000000000111111111100000000001111111111000000000011111111110000000000111111111100000000001111111111000000000011111111110000000000111111111100000000001111111111000000000011111111110000000000111111111100000000001111111111000000000011111111110000000000111111111100000000001111111111000000000011111111110000000000"); //133120 = 2 blocks for testing
	//char *test = get_from_storageServer(s,"test.text",0);
	//printf("\nClient received : %d",sizeof(test));
	//remove_from_storageServer(s,"test.text");
	//close_socket(s);

	puts("Starting application");
	int rv; // return value

	puts("Creating server thread");
	rv = pthread_create (&tarray[0], NULL, (void *)&start_server, NULL);
	if (rv != 0) {
		perror("Error creating thread");
		exit(EXIT_FAILURE);
	}
	puts("Creating client thread");
	rv = pthread_create (&tarray[1], NULL, (void *)&start_client, NULL);
	if (rv != 0) {
		perror("Error creating thread");
		exit(EXIT_FAILURE);
	}
	init_downloader_thread();
	// now wait for all threads to terminate
	int i;
	for (i=0; i < 2; i++) {
		rv = pthread_join(tarray[i], NULL);
		if (rv != 0) {
			perror("Error listening to socket");
			exit(EXIT_FAILURE);
		}
	}
	return(0);
}
